﻿using ComLib.ComFun;
using ComLib.ComType;
using LogLib;
using Newtonsoft.Json;
using PipeClient;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;
using USBControlLib;
using USBControlLib.Settings;
using Button = System.Windows.Forms.Button;

namespace USBControlDemo
{
    public partial class Form1 : Form
    {
        /// <summary>
        /// 当一个应用程序传递数据给另一个应用程序时发送此消息
        /// </summary>
        public const int WM_COPYDATA = 0x004A;

        private IntPtr MonitoringWindowHandle = IntPtr.Zero;

        private const int MSG_ID = 0x1234;

        private USBControlSetting _setting = null;

        private UsbControl usbControl;
        public Form1()
        {
            InitializeComponent();
        }

        public Form1(IntPtr ptr)
        {
            MonitoringWindowHandle = ptr;
            InitializeComponent();        
        }

        private void buttonConnect_Click(object sender, EventArgs e)
        {
            OnConnected();
        }

        private void OnConnected()
        {
            if (usbControl.Init())
            {
                groupBox1.Enabled = true;
                groupBox2.Enabled = true;
                labelActionRes.Text = "连接通断板成功";
                Log.WriteAsync("连接通断板成功");
                buttonConnect.Enabled = false;
                if (MonitoringWindowHandle != IntPtr.Zero)
                {
                    OnAppStartupFinished();
                }
            }
            else
            {
                labelActionRes.Text = $"{usbControl.Error}";
                Log.WriteAsync($"连接通断板失败: {usbControl.Error}");
                if (MonitoringWindowHandle != IntPtr.Zero)
                {
                    OnAppStartupFinished(0, usbControl.Error);
                }               
            }
            if (!string.IsNullOrEmpty(usbControl.VersionInfo))
            {
                labelVerInfo.Text = $"Dll ver: {usbControl.VersionInfo}";
                Log.WriteAsync($"Dll ver: {usbControl.VersionInfo}");
            }
        }

        private void InitComboBoxs()
        {
            comboBoxPorts.Items.Clear();
            string[] ports = SerialPort.GetPortNames();
            comboBoxPorts.Items.AddRange(ports);
            string defaultPortName = $"COM{_setting.SerialPortNum}"; 
            for (int i = 0; i < ports.Length; i++)
            {
                if (ports[i].Equals(defaultPortName))
                {
                    comboBoxPorts.SelectedIndex= i;
                    break;
                }
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            ConfigService config = ConfigService.Get();
            _setting = config.Batch;
            usbControl = new UsbControl(this.Handle);
            InitButtons();
            groupBox1.Enabled = false;
            groupBox2.Enabled = false;
            InitComboBoxs();
            if (MonitoringWindowHandle != IntPtr.Zero)
            {
                OnConnected();
                Log.WriteAsync($"通断板控制程序启动成功, 监视窗口句柄为{MonitoringWindowHandle}");
            }
        }

        private List<Button> listConnectButtons= new List<Button>();

        private List<Button> listDisconnectButtons = new List<Button>();

        private List<Button> listUSBControlButtons = new List<Button>();

        private void InitButtons()
        {
            foreach (var ctl in this.groupBox1.Controls)
            {
                if(ctl is Button)
                {
                    Button btn = (Button)ctl;
                    if(btn.Name.Contains("Connect"))
                    {
                        listConnectButtons.Add(btn);
                    }
                    if (btn.Name.Contains("ControlUSB"))
                    {
                        listUSBControlButtons.Add(btn);
                    }
                    if (btn.Name.Contains("Disconnect"))
                    {
                        listDisconnectButtons.Add(btn);
                    }
                }
            }
            foreach (var ctl in this.groupBox2.Controls)
            {
                if (ctl is Button)
                {
                    Button btn = (Button)ctl;
                    if (btn.Name.Contains("Connect"))
                    {
                        listConnectButtons.Add(btn);
                    }
                    if (btn.Name.Contains("USBControl"))
                    {
                        listUSBControlButtons.Add(btn);
                    }
                    if (btn.Name.Contains("Disconnect"))
                    {
                        listDisconnectButtons.Add(btn);
                    }
                }
            }
            listConnectButtons.Sort((a, b) => a.Name.CompareTo(b.Name));
            listDisconnectButtons.Sort((a, b) => a.Name.CompareTo(b.Name));
            listUSBControlButtons.Sort((a, b) => a.Name.CompareTo(b.Name));
        }

        /// <summary>
        /// 尝试获取按钮的功能类型和索引
        /// </summary>
        /// <param name="btn">需要搜索的按钮</param>
        /// <param name="type">功能类型</param>
        /// <param name="channel">控制的通道</param>
        /// <returns></returns>
        private bool TryFindButtonFunction(Button btn, out int type, out int channel)
        {
            type = 0;
            channel = 0;
            char lastWord = btn.Name.Last();
            if(lastWord > '0' && lastWord < '9')
            {
                channel = lastWord - '0';
            }
            else
            {
                labelActionRes.Text = $"通过{btn.Name}搜索功能失败. ";
                return false;
            }
            if(listConnectButtons.Contains(btn))
            {
                type = 1;
                return true;
            }
            else if (listDisconnectButtons.Contains(btn))
            {
                type = 2;
                return true;
            }
            else if (listUSBControlButtons.Contains(btn))
            {
                type = 3;
                return true;
            }
            else
            {
                labelActionRes.Text = $"通过{btn.Name}搜索功能无效. ";
                return false;
            }
        }

        private async Task DoAction(int type, int channel)
        {         
            if(this.InvokeRequired)
            {
                Func<int, int, Task> handler = new Func<int, int, Task>(DoAction);
                this.BeginInvoke(handler, new object[] { type, channel });
                return;
            }
            SetGroupButtonsEnable(channel, false);
            string actionName = usbControl.GetActionName(type, channel);
            Log.AddBoundary($"开始执行动作：{actionName}");
            labelActionRes.Text = $"开始执行{actionName}, 请稍候...";
            if (await usbControl.TakeAction(type, channel))
            {
                labelActionRes.Text = $"{actionName}成功.";
                Log.WriteAsync($"{usbControl.CurrentFunction}执行成功.");
            }
            else
            {
                labelActionRes.Text = $"{actionName}出错：{usbControl.Error}";
                Log.WriteAsync($"{usbControl.CurrentFunction}执行失败，{usbControl.Error}");
            }
            Log.AddBoundary($"{actionName}动作结束.");
            SetGroupButtonsEnable(channel, true);
        }

        private async void buttonControlUSB_Click(object sender, EventArgs e)
        {
            if(sender == null)
            {
                return;
            }
            if (!usbControl.Connected)
            {                
                return;
            }
            int type = 0;
            int channel = 0;
            Button btn = sender as Button;          
            if (TryFindButtonFunction(btn, out type, out channel))
            {              
                await DoAction(type, channel);              
            }
            else
            {

            }           
        }

        private void SetGroupButtonsEnable(int channel, bool enabled)
        {
            int index = channel - 1;
            List<Button> groupButtons = new List<Button>();
            groupButtons.Add(listConnectButtons[index]);
            groupButtons.Add(listDisconnectButtons[index]);
            groupButtons.Add(listUSBControlButtons[index]);
            for (int i = 0; i < groupButtons.Count; i++)
            {
                Button button = groupButtons[i];
                button.Enabled = enabled;
            }
        }

        private void OnClosing()
        {
            if (usbControl.Connected)
            {
                if (usbControl.Exit())
                {
                    Log.WriteAsync("通断板控制动态库卸载成功.");
                }
                else
                {
                    Log.WriteAsync($"通断板控制动态库卸载失败：{usbControl.Error}.");
                }
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
           
        }

        protected override void WndProc(ref System.Windows.Forms.Message m)
        {
            switch (m.Msg)
            {
                case WM_COPYDATA:
                    OnCustomMsgReceived(m);
                    break;
                case WindowsMessage.WM_CLOSE:
                    OnClosing();
                    break;
                default:
                    break;
            }
            base.WndProc(ref m);
        }

        /// <summary>
        /// 处理来自其他进程发来的消息
        /// </summary>
        /// <param name="m"></param>
        private void OnCustomMsgReceived(System.Windows.Forms.Message m)
        {
            COPYDATASTRUCT mystr = new COPYDATASTRUCT();
            Type mytype = mystr.GetType();
            mystr = (COPYDATASTRUCT)m.GetLParam(mytype);
            string jsonString = mystr.lpData;
            DeviceControlType controlType = (DeviceControlType)(int)m.WParam;
            if (controlType != DeviceControlType.USBControl)
            {
                string logInfo = $"收到的控制命令{controlType}无效.";
                ShowInfo(logInfo);
                Log.WriteAsync(logInfo);
                return;
            }
            try
            {
                USBControlCommandArgs args = JsonConvert.DeserializeObject<USBControlCommandArgs>(jsonString);
                USBControlCommand action = args.Command;
                switch (action)
                {
                    case USBControlCommand.Init:
                        Log.WriteAsync("收到初始化设备的消息");
                        //ShowInfo("收到初始化设备的消息");
                        OnConnected();
                        break;
                    case USBControlCommand.Exit:
                        Log.WriteAsync("收到关闭设备的消息");
                        //ShowInfo("收到关闭设备的消息");
                        this.Close();
                        break;
                    case USBControlCommand.Connect:
                    case USBControlCommand.Disconnect:
                    case USBControlCommand.PullAndPlugIn:
                        Log.WriteAsync("收到执行通断动作的消息");
                        //ShowInfo("收到执行通断动作的消息");
                        OnTakeAction(args);
                        break;
                    default:
                        break;
                }
            }
            catch (Exception ex)
            {
                Log.WriteExceptionAsync(ex.ToString());
            }          
        }

        private void OnTakeAction(USBControlCommandArgs args)
        {
            try
            {
                Task.Run(() => DoAction((int)args.Command, args.Channel));
            }
            catch (Exception ex)
            {
                Log.WriteException(ex.ToString());
            }
        }

        private object _lock = new object();
        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        private static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
        public void ShowInfo(string szText)
        {
            if (this.InvokeRequired)
            {
                Action<string> handler = new Action<string>(ShowInfo);
                this.Invoke(handler, new object[] { szText });
                return;
            }
            labelActionRes.Text = szText;
            lock (_lock)
            {
                DateTime dt = DateTime.Now;
                if (this.richTextBox1.Text.Length > 10000)
                {
                    this.richTextBox1.Text = "";
                }
                this.richTextBox1.Text += dt.ToString("HH:mm:ss") + ": " + szText + "\r\n";
                if (!richTextBox1.IsDisposed)
                {
                    SendMessage(richTextBox1.Handle, 0x0115, 7, 0);
                }
            }
        }

        #region Notify MainForm about something

        /// <summary>
        /// 指示是否已经通知主窗体加载完成
        /// </summary>
        protected bool _bNotified = false;

        private string _appName = Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase);

        /// <summary>
        /// 通知主窗体该进程启动已经完成
        /// </summary>
        protected void OnAppStartupFinished(int code = 1, string msg = "程序加载成功")
        {
            // 当父窗体为空时，不需要通知
            if (IntPtr.Zero == MonitoringWindowHandle || _bNotified)
            {
                Log.WriteAsync(string.Format("{0}获取父进程主窗口句柄为空，不启用进程监测.", _appName));
                return;
            }
            string sendMsg = string.Format("{0}#{1}#{2}", _appName, code, msg);
            var t = new Pipe(8, sendMsg, "MainStartup");
            Task.Factory.StartNew(new Action(t.run));
            Log.WriteAsync("已经通知主窗体启动完成: " + _appName);
            _bNotified = true;
        }
        #endregion
    }
}
